import sys
import random
import time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5 import QtWidgets
from Guy import Guy
from Background import Background
from ComeToScene import ComeToScene
from AllEnemy import AllEnemy
from BulletTouchThread import BulletTouch
from GuyDeath import GuyDeath
from OldGuyDeath import OldGuyDeath
from OldGuy import OldGuy
from TheOldGuyTouchThread import OldGuyThread
from TheGuyTouchThread import TheGuyTouch
from EnemyShootThread import EnemyShootThread


class Game(QGraphicsView):
    def __init__(self):
        super(Game, self).__init__()
        self.root = QFileInfo(__file__).absolutePath()
        self.scene = QGraphicsScene()
        self.bg = Background(self.scene)
        self.AllEnemy = AllEnemy(self.scene)  # 实例化Allenemy以创建敌人对象
        self.aim = QPixmap(self.root + "/res/crosshair.png")  # 加载鼠标图标
        self.myCursor = QCursor(self.aim, -1, -1)  # 实例化QCursor
        self.cts = ComeToScene(self.scene)  # 实例化出场动画
        self.guy = Guy(self.scene)  # 实例化GuyItem并传入当前scene
        self.guydeath = GuyDeath(self.scene)  # 初始化死亡动画
        self.shootsignal = 0  # 发射子弹信号
        self.slidertime = 0  # 计时，滑块滑一分钟
        self.EnemyBulletShoot = 0
        self.label = QLabel(self)
        self.x = 0  # 鼠标位置的x坐标
        self.y = 0  # 鼠标位置的y坐标
        self.Keyx = self.width() * 0.5  # 小人位置的x坐标
        self.Keyy = self.height() * 0.5  # 小人位置的y坐标
        self.rotate = 0
        self.isupdateguyposition = 1  # 是否更新角色位置
        self.isupdateguytouch = 1  # 是否更新角色碰撞检测
        self.isdeath = 0  # 角色是否死亡
        self.enemyrotate = 0  # 跟踪敌人的移动方向
        self.i = 0
        self.MoveSign = 0  # 角色移动信号
        self.updatekeyword = 0  # 是否更新键盘输入
        self.oldguylist = []  # 死亡角色列表
        self.oldguypropertylist = []  # 死亡角色属性列表
        self.guypositonlist = []
        self.guyrotatelist = []
        self.guyshootlist = []
        self.allbulletlist = []  # 所有子弹列表
        self.allguylist = []  # 所有人物角色列表
        self.gameovertip = QGraphicsPixmapItem(QPixmap(self.root + "/res/press_space.png"))  # 死亡后按空格提示
        self.gamethrough = QGraphicsPixmapItem(QPixmap(self.root + "/res/level_cleared.png"))  # 游戏通关
        self.guydeathtime = 0  # 死亡动画时间
        self.updateGuydeathtimer = QTimer(self)  # 角色死亡动画
        self.oldguydeathtime = 0  # 死亡动画时间
        self.updateOldGuydeathtimer = QTimer(self)  # 老角色死亡动画
        self.EnemyUpdata = QTimer(self)  # 发出敌人
        self.rotatingtime = 0  # 出场动画时间
        self.gamelevel = 0  # 游戏关卡数
        self.updateComeToSceneAnimationtimer = QTimer(self)  # 出场动画
        self.CallTimes = 0
        self.updateEnemyTime = 0
        self.UpdateTotalTimer = QTimer(self)  # 总定时器
        self.BulletTouchThread = BulletTouch()  # 实例化子弹碰撞检测线程
        self.IsTheGuyTouch = False  # 角色碰撞信号
        self.TheGuyTouch = TheGuyTouch()  # 实例化小人碰撞检测线程
        self.TheOldGuyTouch = OldGuyThread()  # 实例化老角色碰撞检测和更新线程
        self.EnemyShootThread = EnemyShootThread()

        self.initUI()

    def initUI(self):
        self.setFixedSize(1600, 900)
        self.setWindowTitle("game")
        self.setWindowIcon(QIcon(self.root + "/res/doom_guy.png"))  # 设置游戏图标

        self.scene.addItem(self.gameovertip)
        self.scene.addItem(self.gamethrough)
        self.gameovertip.setVisible(False)
        self.gameovertip.setPos(100, 650)
        self.gamethrough.setVisible(False)
        self.gamethrough.setPos(515, 350)

        self.scene.setSceneRect(0, 0, self.width() - 2, self.height() - 2)
        self.setScene(self.scene)

        self.cts.setPos(QPoint(800, 450))  # 放置
        self.guydeath.setPos(QPoint(800, 450))

        self.setMouseTracking(True)  # 鼠标信号跟踪事件设为True

        self.label.setGeometry(10, 10, 200, 40)

        self.guy.setPos(QPointF(self.Keyx, self.Keyy))  # 设置小人坐标(Item中setPos函数就是设置坐标函数)
        self.guyComeToScenePos()  # 角色出场位置随机
        self.allbulletlist += self.guy.bulletlist

        self.aim = self.aim.scaled(35, 35, Qt.KeepAspectRatio)  # 这个忘记什么功能了

        self.setCursor(self.myCursor)  # 将实例化的Qcursor绑定窗口

        self.UpdateTotalTimer.timeout.connect(self.TotalTimer)

        self.updateComeToSceneAnimationtimer.timeout.connect(self.ComeToSceneAnimation)
        self.updateComeToSceneAnimationtimer.start(20)

        self.EnemyUpdata.timeout.connect(self.CallEnemySet)
        self.EnemyUpdata.start(1500)

        self.updateGuydeathtimer.timeout.connect(self.GuyDeathAnimation)
        self.updateOldGuydeathtimer.timeout.connect(self.OldGuyDeathAnimation)

        self.BulletTouchThread.sin.connect(self.IsBulletTouchThread)  # 连接槽函数
        # 角色碰撞线程初始化
        self.TheGuyTouch.getGuy(self.guy)
        self.TheGuyTouch.sin.connect(self.GuyTouch)  # 与guyTouch绑定
        # 老角色碰撞线程初始化
        self.TheOldGuyTouch.signal.connect(self.OldGuyTouch)  # 与oldguyTouch绑定

        self.UpdateTotalTimer.start(5)

        self.updateOldGuydeathtimer.start(100)

    def TotalTimer(self):  # 总计时器,每五毫秒刷新一次
        self.EnemyBulletShoot = (self.EnemyBulletShoot + 1) % 400
        if self.EnemyBulletShoot == 0:
            self.EnemyShootThread.SetAllEnemy(self.AllEnemy)
            self.EnemyShootThread.start()

        self.UpdateEnemyRotate()
        self.scene.advance()  # 更新子弹和敌人坐标
        self.updateslider()  # 更新滑块

        # 更新角色坐标位置
        qline = QLineF(self.x, self.y, self.Keyx, self.Keyy)
        self.rotate = 180 - qline.angle()

        if self.isupdateguyposition == 1:  # 判断是否更新角色位置坐标
            self.guy.setState(self.rotate)  # 更新角色移动状态
            self.updateGuyPos()
            self.Shooting()  # 射击
        if self.isupdateguytouch == 1:  # 判断是否启动角色碰撞检测线程
            self.TheGuyTouch.getList(self.AllEnemy.EnemySetList)
            self.TheGuyTouch.start()
        if self.guy.isdeath == 0 and self.updatekeyword == 1:
            # 角色移动
            if self.MoveSign == 1:
                self.Keyx -= 8
            elif self.MoveSign == 2:
                self.Keyy -= 8
            elif self.MoveSign == 3:
                self.Keyx -= 6
                self.Keyy -= 6
            elif self.MoveSign == 4:
                self.Keyy += 8
            elif self.MoveSign == 5:
                self.Keyx -= 6
                self.Keyy += 6
            elif self.MoveSign == 6:
                self.Keyx += 8
            elif self.MoveSign == 8:
                self.Keyx += 6
                self.Keyy -= 6
            elif self.MoveSign == 10:
                self.Keyx += 6
                self.Keyy += 6

            self.guypositonlist.append(QPointF(self.Keyx, self.Keyy))
            self.guyrotatelist.append(self.rotate)
            self.guyshootlist.append(self.shootsignal)
            self.UpdateOldGuy()
        if len(self.oldguylist) > 0:
            self.TheOldGuyTouch.getList(self.AllEnemy.EnemySetList, self.oldguylist)
            self.TheOldGuyTouch.start()

        # 启动子弹碰撞检测线程
        self.BulletTouchThread.getList(self.allbulletlist, self.AllEnemy.EnemySetList)
        self.BulletTouchThread.start()

    def guyComeToScenePos(self):  # 计算小人出现的位置
        random.seed(time.time())
        x = random.randint(150, 1450)
        y = random.randint(150, 780)
        self.Keyx = x
        self.Keyy = y
        self.cts.setPos(QPointF(x, y))
        self.guy.setPos(QPointF(x, y))

    def ComeToSceneAnimation(self):  # 出场动画
        self.rotatingtime += 1
        if self.rotatingtime == 50:
            self.updatekeyword = 1   # 更新键盘
            self.updateComeToSceneAnimationtimer.stop()  # 停止动画
            # self.MoveSign = 0
            self.isupdateguytouch = 1  # 碰撞检测
            self.isupdateguyposition = 1  # 更新坐标位置
            self.slidertime = 0  # 重置滑块时间
            self.AllEnemy.SetLevelSymbol(self.gamelevel+1)  # 设置游戏关卡
            for i in range(len(self.oldguylist)):
                self.oldguylist[i].isdeath = 0
                self.oldguylist[i].setVisible(True)

            # self.TheOldGuyThread.getList(self.AllEnemy.EnemySetList, self.oldguylist, self.oldguypropertylist)

        else:
            self.cts.updateAnimation()
            self.guy.updateAnimation()

    def updateslider(self):  # 更新滑块，每5毫秒调用一次
        self.slidertime += 1
        if self.slidertime > 11650:
            self.UpdateTotalTimer.stop()
            if self.guy.isdeath == 0:
                self.gamethrough.setVisible(True)
        else:
            self.bg.updateslider()  # 此函数实现背景中的滑块前进

    def GuyDeathAnimation(self):  # 角色死亡动画
        self.guydeathtime += 1
        if self.guydeathtime == 6:
            self.guydeathtime = 0
            self.guydeath.setVisible(False)
            self.updateGuydeathtimer.stop()
            self.gameovertip.setVisible(True)
        else:
            self.guydeath.updateDeathAnimation()

    def OldGuyDeathAnimation(self):  # 角色死亡动画
        for oldguy in self.oldguylist:
            oldguy.updateDeathAnimation()

    def GuyTouch(self, istouch):  # 角色碰撞检测
        self.IsTheGuyTouch = istouch
        if self.IsTheGuyTouch:
            self.updatekeyword = 0  # 不更新键盘
            self.guy.isdeath = 1  # 死亡信号，已死亡
            self.isupdateguytouch = 0  # 不更新碰撞检测
            self.isupdateguyposition = 0  # 不更新坐标位置
            self.i = 0
            self.AddOldGuy()  # 添加老角色
            self.guydeath.setVisible(True)
            self.guydeath.setPos(QPointF(self.Keyx, self.Keyy))  # 设置死亡动画位置
            for i in range(len(self.oldguylist)):
                self.oldguylist[i].setVisible(False)
            self.updateGuydeathtimer.start(100)

    def OldGuyTouch(self, i, x, y):  # 角色碰撞检测
        self.oldguydeath = OldGuyDeath(self.scene)
        self.oldguydeath.setVisible(True)
        self.oldguydeath.setPos(QPointF(x, y))
        self.oldguydeadbodylist[i].setVisible(True)
        self.oldguydeadbodylist[i].setPos(QPointF(x - 42.5, y - 47.5))
        self.updateOldGuydeathtimer.start(100)

    def updateGuyPos(self):  # 更新角色位置并进行边界检测
        # 边界检测
        if self.Keyx + self.guy.pix.width() * 0.5 > self.width():
            self.Keyx = self.width() - self.guy.pix.width() * 0.5
        elif self.Keyy + self.guy.pix.width() * 0.5 > self.height():
            self.Keyy = self.height() - self.guy.pix.width() * 0.5
        elif self.Keyx - self.guy.pix.width() * 0.5 < 0:
            self.Keyx = self.guy.pix.width() * 0.5
        elif self.Keyy - self.guy.pix.width() * 0.5 < 0:
            self.Keyy = self.guy.pix.width() * 0.5
        self.guy.setPos(QPointF(self.Keyx, self.Keyy))  # 更新角色坐标
        # 在updataguypos里面更新子弹测试碰撞

    def UpdateEnemyRotate(self):
        for i in range(20):
            for Enemy in self.AllEnemy.EnemySetList[i + 10].EnemyList:
                if self.guy.isdeath == 0:
                    Keypoint = QPointF(self.Keyx, self.Keyy)
                    EnemyQline = QLineF(Enemy.mapToScene(0, 0), Keypoint)
                    self.enemyrotate = -EnemyQline.angle()
                Enemy.setRotation(self.enemyrotate)

    def IsBulletTouchThread(self, x, y):  # 与BulletTouchThread相连的槽函数实现两个集合的重新赋值
        self.guy.bulletlist = x  # 重新赋值
        self.AllEnemy.EnemySetList = y

    def CallEnemySet(self):  # 利用CallSet函数实例化敌人集合
        if self.updateEnemyTime == 0:
            self.AllEnemy.CallSmallEnemySet()
        elif self.updateEnemyTime == 1:
            self.AllEnemy.CallSmallEnemy()
            self.AllEnemy.CallFollowEnemySet()
        elif self.updateEnemyTime == 2:
            #self.AllEnemy.CallSmallEnemySet()
            self.AllEnemy.CallBigEnemySet()
        else:
            self.AllEnemy.CallSmallEnemy()
            #self.AllEnemy.CallSmallEnemySet()

        self.updateEnemyTime = (self.updateEnemyTime + 1) % 4  # 可改参数调整出场顺序

    def Shooting(self):  # 实现发射子弹,当shootsignal为1发射
        if self.shootsignal == 1:
            self.guy.Shooting()

    def AddOldGuy(self):
        guyproperty = [self.guypositonlist, self.guyrotatelist, self.guyshootlist]  # 一个老角色的属性列表
        self.oldguypropertylist.append(guyproperty)  # 添加到属性列表
        oldguy = OldGuy(self.scene)
        oldguy.setVisible(False)
        self.allbulletlist += oldguy.bulletlist
        self.oldguylist.append(oldguy)  # 创建一个角色并添加到角色列表
        self.guypositonlist = []
        self.guyrotatelist = []
        self.guyshootlist = []

    def UpdateOldGuy(self):
        for index in range(len(self.oldguylist)):
            if self.i < len(self.oldguypropertylist[index][0]) and self.oldguylist[index].isdeath == 0:
                pos = self.oldguypropertylist[index][0][self.i]
                rotate = self.oldguypropertylist[index][1][self.i]
                shoot = self.oldguypropertylist[index][2][self.i]
                self.oldguylist[index].setPos(pos)
                self.oldguylist[index].setState(rotate)
                if shoot == 1:
                    self.oldguylist[index].Shooting()
            else:
                pass

        self.i += 1

    def RestartAllEnemy(self):
        for enemyset in self.AllEnemy.EnemySetList:
            for enemy in enemyset.EnemyList:
                enemy.setVisible(False)
        self.AllEnemy.callTime = 0  # 记录第几次调用
        self.AllEnemy.callTimetwo = 0
        self.updateEnemyTime = 0

    def RestartGame(self):
        pass

    def mouseReleaseEvent(self, e):  # 更改射击状态(shootsignal=0)
        self.shootsignal = 0  # 松开解除发射状态

    def mousePressEvent(self, e):  # 改变朝向以及更改射击状态(shootsignal=1)
        self.x = e.x()
        self.y = e.y()
        qline = QLineF(self.x, self.y, self.Keyx, self.Keyy)
        self.rotate = 180 - qline.angle()
        self.shootsignal = 1  # 按下发射

    def mouseMoveEvent(self, e):  # 控制朝向（改变rotate的值）

        self.x = e.x()
        self.y = e.y()
        text = "x: {0},  y: {1}".format(self.x - self.width() * 0.5, self.y - self.height() * 0.5)  # 这里更改为self
        self.label.setText(text)  # 更改label
        qline = QLineF(self.x, self.y, self.Keyx, self.Keyy)
        self.rotate = 180 - qline.angle()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_A:
            self.MoveSign -= 1
        elif event.key() == Qt.Key_W:
            self.MoveSign -= 2
        elif event.key() == Qt.Key_S:
            self.MoveSign -= 4
        elif event.key() == Qt.Key_D:
            self.MoveSign -= 6

    def keyPressEvent(self, QKeyEvent):  # 方向控制
        # 8个移动方向

        if QKeyEvent.key() == Qt.Key_A:
            self.MoveSign += 1
            # self.Keyx -= 20
        elif QKeyEvent.key() == Qt.Key_W:
            self.MoveSign += 2
            # self.Keyx += 20
        elif QKeyEvent.key() == Qt.Key_S:
            self.MoveSign += 4
        elif QKeyEvent.key() == Qt.Key_D:
            self.MoveSign += 6
        if self.guy.isdeath == 0 and self.slidertime > 11650 and self.gamelevel < 2 and QKeyEvent.key() == Qt.Key_Space:
            self.RestartAllEnemy()  # 重置敌人
            self.gamelevel = (self.gamelevel + 1) % 3
            self.guy.opacity = 0  # 设置角色透明度为零
            self.cts.rotatespeed = 10  # 旋转速度
            self.cts.opacity = 1  # 设置旋转透明度
            self.rotatingtime = 0  # 出场动画时间
            self.guy.state_index1 = 0  # 记录小人面向的方向
            self.guy.state_index2 = 0  # 记录小人当前处于哪一种移动状态
            self.guy.setVisible(True)
            self.gamethrough.setVisible(False)
            self.slidertime = 0  # 重新设置滑块时间
            self.bg.sliderx = 294  # 重新设置滑块位置
            self.guy.isdeath = 0  # 未死亡
            self.oldguylist = []
            self.oldguypropertylist = []
            self.guypositonlist = []
            self.guyrotatelist = []
            self.guyshootlist = []
            self.UpdateTotalTimer.start()
            self.guyComeToScenePos()
            self.updateComeToSceneAnimationtimer.start(20)  # 出场动画
        if self.guy.isdeath == 1:
            if QKeyEvent.key() == Qt.Key_Space:
                self.guy.isdeath = 2  # 死亡信号，已死亡
                self.guy.opacity = 0  # 设置角色透明度为零
                self.cts.rotatespeed = 10  # 旋转速度
                self.cts.opacity = 1  # 设置旋转透明度
                self.rotatingtime = 0  # 出场动画时间
                self.guy.state_index1 = 0  # 记录小人面向的方向
                self.guy.state_index2 = 0  # 记录小人当前处于哪一种移动状态
                self.guy.setVisible(True)
                self.slidertime = 0  # 重新设置滑块时间
                self.bg.sliderx = 294  # 重新设置滑块位置
                self.guy.isdeath = 0  # 未死亡
                self.gameovertip.setVisible(False)

                self.RestartAllEnemy()  # 重置敌人

                self.guyComeToScenePos()
                self.updateComeToSceneAnimationtimer.start(20)  # 出场动画



if __name__ == "__main__":
    try:
        app = QApplication(sys.argv)
        game = Game()
        game.show()
        sys.exit(app.exec_())
    except Exception as e:
        print(e)
